package example.config;

import org.apache.dubbo.config.annotation.Reference;
import org.springframework.aop.support.AopUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanCreationException;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.lang.reflect.Field;

@Configuration
public class FakeDubboAutoConfig implements ApplicationContextAware {

    ApplicationContext applicationContext;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }

    @Bean
    public BeanPostProcessor beanPostProcessor() {
        return new BeanPostProcessor() {
            @Override
            public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
                Class<?> objClz;
                if (AopUtils.isAopProxy(bean)) {
                    objClz = AopUtils.getTargetClass(bean);
                } else {
                    objClz = bean.getClass();
                }

                try {
                    for (Field field : objClz.getDeclaredFields()) {
                        //判断该字段是否有 Reference 注解
                        Reference reference = field.getAnnotation(Reference.class);
                        if (reference != null) {
                            Object localBean = applicationContext.getBean(field.getType());
                            if(localBean != null) {
                                field.setAccessible(true);
                                field.set(bean, localBean);
                            } else {
                                throw new NoSuchBeanDefinitionException(field.getName());
                            }
                        }
                    }
                } catch (Exception e) {
                    throw new BeanCreationException(beanName, e);
                }
                return bean;
            }
        };
    }

}
